package com.eduagent.xwqeduagent.api.characterRecognition.FormulaRecognition;

import com.eduagent.xwqeduagent.api.characterRecognition.FormulaRecognition.demo.FileUtil;
import com.eduagent.xwqeduagent.api.characterRecognition.FormulaRecognition.demo.HttpUtil;
import com.google.gson.Gson;
import com.google.gson.JsonObject;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 公式识别API接口实现类
 */
public class FormulaRecognitionAPI {
    // 公式识别webapi接口地址
    private static final String FORMULA_RECOGNITION_URL = "https://rest-api.xfyun.cn/v2/itr";
    
    // 应用ID
    private String appId;
    
    // 接口密钥
    private String apiKey;
    
    // 接口APISecret
    private String apiSecret;
    
    /**
     * 构造函数
     * 
     * @param appId     应用ID
     * @param apiKey    接口密钥
     * @param apiSecret 接口密钥
     */
    public FormulaRecognitionAPI(String appId, String apiKey, String apiSecret) {
        this.appId = appId;
        this.apiKey = apiKey;
        this.apiSecret = apiSecret;
    }
    
    /**
     * 从二进制数据识别公式
     * 
     * @param imageByteArray 图片二进制数据
     * @return 识别结果JSON字符串
     * @throws Exception 
     */
    public String recognizeFromByteArray(byte[] imageByteArray) throws Exception {
        // 构建HTTP请求体
        String body = buildHttpBody(imageByteArray);
        
        // 构建HTTP请求头
        Map<String, String> header = buildHttpHeader(body);
        
        // 发送HTTP请求
        Map<String, Object> resultMap = HttpUtil.doPost2(FORMULA_RECOGNITION_URL, header, body);
        
        if (resultMap != null) {
            return resultMap.get("body").toString();
        } else {
            throw new Exception("调用公式识别API失败");
        }
    }
    
    /**
     * 构建HTTP请求体
     * 
     * @param imageByteArray 图片二进制数据
     * @return 请求体JSON字符串
     */
    private String buildHttpBody(byte[] imageByteArray) {
        JsonObject body = new JsonObject();
        JsonObject business = new JsonObject();
        JsonObject common = new JsonObject();
        JsonObject data = new JsonObject();
        
        // 填充common
        common.addProperty("app_id", appId);
        
        // 填充business
        business.addProperty("ent", "teach-photo-print");
        business.addProperty("aue", "raw");
        
        // 填充data
        String imageBase64 = Base64.getEncoder().encodeToString(imageByteArray);
        data.addProperty("image", imageBase64);
        
        // 填充body
        body.add("common", common);
        body.add("business", business);
        body.add("data", data);
        
        return body.toString();
    }
    
    /**
     * 构建HTTP请求头
     * 
     * @param body 请求体
     * @return HTTP请求头
     * @throws Exception
     */
    private Map<String, String> buildHttpHeader(String body) throws Exception {
        Map<String, String> header = new HashMap<>();
        URL url = new URL(FORMULA_RECOGNITION_URL);

        // 时间戳
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        Date dateD = new Date();
        String date = format.format(dateD);

        // 对body进行sha256签名,生成digest头部
        String digestBase64 = "SHA-256=" + signBody(body);

        // hmacsha256加密原始字符串
        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n")
                .append("date: ").append(date).append("\n")
                .append("POST ").append(url.getPath()).append(" HTTP/1.1").append("\n")
                .append("digest: ").append(digestBase64);
        String sha = hmacsign(builder.toString(), apiSecret);

        // 组装authorization
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                apiKey, "hmac-sha256", "host date request-line digest", sha);

        header.put("Authorization", authorization);
        header.put("Content-Type", "application/json");
        header.put("Accept", "application/json,version=1.0");
        header.put("Host", url.getHost());
        header.put("Date", date);
        header.put("Digest", digestBase64);
        
        return header;
    }
    
    /**
     * 对body进行SHA-256加密
     * 
     * @param body 请求体
     * @return 加密后的字符串
     * @throws Exception
     */
    private String signBody(String body) throws Exception {
        MessageDigest messageDigest;
        String encodestr = "";
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(body.getBytes("UTF-8"));
            encodestr = Base64.getEncoder().encodeToString(messageDigest.digest());
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            throw e;
        }
        return encodestr;
    }
    
    /**
     * hmacsha256加密
     * 
     * @param signature 签名字符串
     * @param apiSecret 接口密钥
     * @return 加密后的字符串
     * @throws Exception
     */
    private String hmacsign(String signature, String apiSecret) throws Exception {
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(signature.getBytes(charset));
        return Base64.getEncoder().encodeToString(hexDigits);
    }
    
    /**
     * 从Base64编码识别公式
     * 
     * @param base64Image Base64编码的图片数据
     * @return 识别结果JSON字符串
     * @throws Exception
     */
    public String recognizeFromBase64(String base64Image) throws Exception {
        // 解码Base64数据
        byte[] imageByteArray = Base64.getDecoder().decode(base64Image);
        
        return recognizeFromByteArray(imageByteArray);
    }
} 